home *** CD-ROM | disk | FTP | other *** search
/ Atari Mega Archive 2 / Atari Mega Archive CD - Volume 2.iso / minix / up1510b.tgz / up1510b / src / commands / nroff / macros.c < prev    next >
C/C++ Source or Header  |  1990-07-23  |  9KB  |  518 lines

  1. /*
  2.  *    macros.c - macro input/output processing for nroff word processor
  3.  *
  4.  *    adapted for atariST/TOS by Bill Rosenkranz 11/89
  5.  *    net:    rosenkra@hall.cray.com
  6.  *    CIS:    71460,17
  7.  *    GENIE:    W.ROSENKRANZ
  8.  *
  9.  *    original author:
  10.  *
  11.  *    Stephen L. Browning
  12.  *    5723 North Parker Avenue
  13.  *    Indianapolis, Indiana 46220
  14.  *
  15.  *    history:
  16.  *
  17.  *    - Originally written in BDS C;
  18.  *    - Adapted for standard C by W. N. Paul
  19.  *    - Heavily hacked up to conform to "real" nroff by Bill Rosenkranz
  20.  *    - Changed array index i from type long to type int (32000 is the
  21.  *      largest value anyhow) to prevent compiler warnings
  22.  *      by Wim 'Blue Baron' van Dorst (wsincc@tuerc3.urc.tue.nl)
  23.  */
  24.  
  25. #undef NRO_MAIN                    /* extern globals */
  26.  
  27. #include <stdio.h>
  28. #include "nroff.h"
  29.  
  30.  
  31.  
  32. /*------------------------------*/
  33. /*    defmac            */
  34. /*------------------------------*/
  35. defmac (p, infp)
  36. register char  *p;
  37. FILE           *infp;
  38. {
  39.  
  40. /*
  41.  *    Define a macro. top level, read from stream.
  42.  *
  43.  *    we should read macro without interpretation EXCEPT:
  44.  *
  45.  *    1) number registers are interpolated
  46.  *    2) strings indicated by \* are interpolated
  47.  *    3) arguments indicated by \$ are interpolated
  48.  *    4) concealed newlines indicated by \(newline) are eliminated
  49.  *    5) comments indicated by \" are eliminated
  50.  *    6) \t and \a are interpreted as ASCII h tab and SOH.
  51.  *    7) \\ is interpreted as backslash and \. is interpreted as a period.
  52.  *
  53.  *    currently, we do only 3. a good place to do it would be here before
  54.  *    putmac, after colmac...
  55.  */
  56.  
  57.     register char  *q;
  58.     register int    i;
  59.     char        name[MNLEN];
  60.     char        defn[MXMLEN];
  61.     char        newend[10];
  62.  
  63.  
  64.     /*
  65.      *   skip the .de and get to the name...
  66.      */
  67.     q = skipwd (p);
  68.     q = skipbl (q);
  69.  
  70.     /*
  71.      *   ok, name now holds the name. make sure it is valid (i.e. first
  72.      *   char is alpha...). getwrd returns the length of the word.
  73.      */
  74.     i = getwrd (q, name);
  75.     if (!isprint (*name))
  76.     {
  77.         fprintf (err_stream,
  78.             "***%s: missing or illegal macro definition name\n",
  79.             myname);
  80.         err_exit (-1);
  81.     }
  82.  
  83.     /*
  84.      *   truncate to 2 char max name.
  85.      */
  86.     if (i > 2)
  87.         name[2] = EOS;
  88.  
  89.  
  90.     /*
  91.      *   skip the name and see if we have a new end defined...
  92.      */
  93.     q = skipwd (p);
  94.     q = skipbl (q);
  95.     for (i = 0; i < 10; i++)
  96.         newend[i] = EOS;
  97.  
  98.     for (i = 0; (i < 10) && ( isalpha (q[i]) || isdigit (q[i]) ); i++)
  99.     {
  100.         newend[i] = q[i];
  101.     }
  102.  
  103.  
  104.  
  105.     /*
  106.      *   read a line from input stream until we get the end of macro
  107.      *   command (.en or ..). actually. we should have read the next
  108.      *   field just above here to get the .de NA . or .de NA en string
  109.      *   to be new end of macro.
  110.      */
  111.     i = 0;
  112.     while (getlin (p, infp) != EOF)
  113.     {
  114.         if (p[0] == dc.cmdchr && newend[0] != EOS
  115.         &&  p[1] == newend[0] && p[2] == newend[1])
  116.         {
  117.             /*
  118.              *   replacement end found
  119.              */
  120.             break;
  121.         }
  122.         if (p[0] == dc.cmdchr && p[1] == 'e' && p[2] == 'n')
  123.         {
  124.             /*
  125.              *   .en found
  126.              */
  127.             break;
  128.         }
  129.         if (p[0] == dc.cmdchr && p[1] == dc.cmdchr)
  130.         {
  131.             /*
  132.              *   .. found
  133.              */
  134.             break;
  135.         }
  136.  
  137.  
  138.         /*
  139.          *   collect macro from the line we just read. all this does
  140.          *   is put it in the string defn.
  141.          */
  142.         if ((i = colmac (p, defn, i)) == ERR)
  143.         {
  144.             fprintf (err_stream,
  145.                 "***%s: macro definition too long\n", myname);
  146.             err_exit (-1);
  147.         }
  148.     }
  149.  
  150.  
  151.     /*
  152.      *   store the macro
  153.      */
  154.     if (!ignoring)
  155.     {
  156.         if (putmac (name, defn) == ERR)
  157.         {
  158.             fprintf (err_stream,
  159.                 "***%s: macro definition table full\n", myname);
  160.             err_exit (-1);
  161.         }
  162.     }
  163. }
  164.  
  165.  
  166.  
  167.  
  168.  
  169. /*------------------------------*/
  170. /*    colmac            */
  171. /*------------------------------*/
  172. colmac (p, d, i)
  173. register char  *p;
  174. char           *d;
  175. register int    i;
  176. {
  177.  
  178. /*
  179.  *    Collect macro definition from input stream
  180.  */
  181.  
  182.     while (*p != EOS)
  183.     {
  184.         if (i >= MXMLEN - 1)
  185.         {
  186.             d[i - 1] = EOS;
  187.             return (ERR);
  188.         }
  189.         d[i++] = *p++;
  190.     }
  191.     d[i] = EOS;
  192.     return (i);
  193. }
  194.  
  195.  
  196.  
  197.  
  198.  
  199. /*------------------------------*/
  200. /*    putmac            */
  201. /*------------------------------*/
  202. putmac (name, p)
  203. char   *name;
  204. char   *p;
  205. {
  206.  
  207. /*
  208.  *    Put macro definition into table
  209.  *
  210.  *    NOTE: any expansions of things like number registers SHOULD
  211.  *    have been done already.
  212.  */
  213.  
  214.  
  215.     /*
  216.      *   any room left? (did we exceed max number of possible macros)
  217.      */
  218.     if (mac.lastp >= MXMDEF)
  219.         return (ERR);
  220.  
  221.     /*
  222.      *   will new one fit in big buffer?
  223.      */
  224.     if (mac.emb + strlen (name) + strlen (p) + 1 > &mac.mb[MACBUF])
  225.     {
  226.         return (ERR);
  227.     }
  228.  
  229.  
  230.     /*
  231.      *   add it...
  232.      *
  233.      *   bump counter, set ptr to name, copy name, copy def.
  234.      *   finally increment end of macro buffer ptr (emb).
  235.      *
  236.      *   macro looks like this in mb:
  237.      *
  238.      *    mac.mb[MACBUF]        size of total buf
  239.      *    lastp < MXMDEF        number of macros possible
  240.      *    *mnames[MXMDEF]        -> names, each max length
  241.      *    ..._____________________________...____________________...
  242.      *        / / /|X|X|0|macro definition      |0| / / / / / / /
  243.      *    .../_/_/_|_|_|_|________________...___|_|/_/_/_/_/_/_/_...
  244.      *          ^
  245.      *          |
  246.      *          \----- mac.mnames[mac.lastp] points here
  247.      *
  248.      *   both the 2 char name (XX) and the descripton are null term and
  249.      *   follow one after the other.
  250.      */
  251.     ++mac.lastp;
  252.     mac.mnames[mac.lastp] = mac.emb;
  253.     strcpy (mac.emb, name);
  254.     strcpy (mac.emb + strlen (name) + 1, p);
  255.     mac.emb += strlen (name) + strlen (p) + 2;
  256.  
  257.     return (OK);
  258. }
  259.  
  260.  
  261.  
  262.  
  263.  
  264.  
  265. /*------------------------------*/
  266. /*    getmac            */
  267. /*------------------------------*/
  268. char   *getmac (name)
  269. register char  *name;
  270. {
  271.  
  272. /*
  273.  *    Get (lookup) macro definition from namespace
  274.  */
  275.  
  276.     register int    i;
  277.  
  278.     /*
  279.      *   loop for all macros, starting with last one
  280.      */
  281.     for (i = mac.lastp; i >= 0; --i)
  282.     {
  283.         /*
  284.          *   is this REALLY a macro?
  285.          */
  286.         if (mac.mnames[i])
  287.         {
  288.             /*
  289.              *   if it compares, return a ptr to it
  290.              */
  291.             if (!strcmp (name, mac.mnames[i]))
  292.             {
  293. /*!!!debug            puts (mac.mnames[i]);*/
  294.  
  295.                 if (mac.mnames[i][1] == EOS)
  296.                     return (mac.mnames[i] + 2);
  297.                 else
  298.                     return (mac.mnames[i] + 3);
  299.             }
  300.         }
  301.     }
  302.  
  303.     /*
  304.      *   none found, return null
  305.      */
  306.     return (NULL_CPTR);
  307. }
  308.  
  309.  
  310.  
  311.  
  312.  
  313.  
  314. /*------------------------------*/
  315. /*    maceval            */
  316. /*------------------------------*/
  317. maceval (p, m)
  318. register char  *p;
  319. char           *m;
  320. {
  321.  
  322. /*
  323.  *    Evaluate macro expansion
  324.  */
  325.  
  326.     register int    i;
  327.     register int    j;
  328.     char           *argp[15];
  329.     char        c;
  330.     int        xc;
  331.  
  332.  
  333.  
  334.     /*
  335.      *   replace command char with EOS
  336.      */
  337.     *p++ = EOS;
  338.  
  339.  
  340.     /* 
  341.      *   initialize argp array to substitute command
  342.      *   string for any undefined argument
  343.      *
  344.      *    NO!!! this is fixed...
  345.      */
  346. /*    for (i = 0; i < 10; ++i)
  347.         argp[i] = p;
  348. */
  349.     /*
  350.      *   skip the command name
  351.      */
  352.     p = skipwd (p);
  353.     *p++ = EOS;
  354.  
  355.  
  356.     /*
  357.      *   loop for all $n variables...
  358.      */
  359.     for (i = 0; i < 10; ++i)
  360.     {
  361.         /*
  362.          *   get to substituted param and if no more, reset remaining
  363.          *   args to NULL and stop. using "i" here IS ok...
  364.          */
  365.         p = skipbl (p);
  366.         if (*p == '\r' || *p == '\n' || *p == EOS)
  367.         {
  368.             set_ireg (".$", i, 0);
  369.             for ( ; i < 10; i++)
  370.             {
  371.                 argp[i] = NULL_CPTR;
  372.             }
  373.             break;
  374.         }
  375.  
  376.  
  377.         /*
  378.          *   ...otherwise, see if this param is quoted. if it is,
  379.          *   it is all one parameter, even with blanks (but not
  380.          *   newlines...). look for another "c" (which is the quote).
  381.          *
  382.          *   if no quote, just read the arg as a single word and null
  383.          *   terminate it.
  384.          */
  385.         if (*p == '\'' || *p == '"')
  386.         {
  387.             c = *p++;
  388.             argp[i] = p;
  389.             while (*p != c && *p != '\r' && *p != '\n' && *p != EOS)
  390.                 ++p;
  391.             *p++ = EOS;
  392.         }
  393.         else
  394.         {
  395.             argp[i] = p;
  396.             p = skipwd (p);
  397.             *p++ = EOS;
  398.         }
  399.     }
  400.  
  401.  
  402.     /*
  403.      *   m contains text of the macro. p contained the input line.
  404.      *   here we start at the end of the macro def and see if there
  405.      *   are any $n thingies. go backwards.
  406.      */
  407.     for (i = strlen (m) - 1; i >= 0; --i)
  408.     {
  409.         /*
  410.          *   found a $.
  411.          */
  412.         if (i > 0 && m[i - 1] == '$')
  413.         {
  414.             if (!isdigit (m[i]))
  415.             {
  416.                 /*
  417.                  *   it wasn't a numeric replacement arg so
  418.                  *   push this char back onto input stream
  419.                  */
  420.                 putbak (m[i]);
  421.             }
  422.             else
  423.             {
  424.                 /*
  425.                  *   it WAS a numeric replacement arg. so we
  426.                  *   want to push back the appropriate macro
  427.                  *   invocation arg. m[i]-'0' is the numerical
  428.                  *   value of the $1 thru $9. if the arg is
  429.                  *   not there, argp[n] will be (char *) 0
  430.                  *   and pbstr will do nothing.
  431.                  */
  432.                 xc = m[i] - '1';
  433.                 if (argp[xc])
  434.                     pbstr (argp[xc]);
  435.                 --i;
  436.             }
  437.         }
  438.         else
  439.         {
  440.             /*
  441.              *   no $ so push back the char...
  442.              */
  443.             putbak (m[i]);
  444.         }
  445.     }
  446.  
  447.     /*
  448.      *   at this point